#ifndef ADD_H_
#define ADD_H_

#include "vehicleState.h"
#include "tabooList.h"
#include "gMatrix.h"
#include "los.h"

/** Numero di iterazioni di tenure per gli archi aggiunti nella mossa ADD con sottotipo Double.
 * è importantissimo che questo valore sia nullo, o si genereranno outputs pieni di archi doppi!!!!
 * Quando andremo a sistemare queste macro come valori letti da un file, questa macro NON sarà toccata!! */
#define ADD_DOUBLE_ADDTENURE 0

/**TODO modificare questa definizione. Difatti l'arco triangolante su nodi già nel percorso non aggiunge dei nodi al totale
 * il file racchiude tutte le funzioni, le variabili e i simboli usati per gestire la mossa Add. Come da manuale, una mossa viene definita add(n)
 * se aggiunge alla soluzione originale n numero di nodi (eventualmente mai attraversati dalla soluzione). L'add qui implementato e' l'add(1) cioe' l'inclusione
 * di un singolo nodo nella soluzione. L'inclusione di un solo nodo genera in realta' 3 sottocasi:
 * 1) l'eliminazione di un arco e l'inclusione di 2
 * 2) l'inclusione di 2 archi da un nodo di inizio
 * 3) l'inclusione di 2 archi da un nodo di fine
 * Per ulteriori informazioni riguardo l'add, vedere il manuale.
 */
/**computa l'intorno della soluzione tramite un intorno add e ricava il migliore stato possibile per il veicolo
 *
 * @param graph indica il grafo su cui computare il nuovo intorno. Non inserire valore NULL
 * @param now è l'iterazione STM corrente, usata per approciarsi alla taboolist.
 * @param vehicleState indica lo stato di un veicolo, utilizzato come centro dell'intorno. Non inserire valore NULL.
 * 			Attenzione: questo stato, a meno che la mossa fallisca (supponiamo possa fallire per mille motivi) sarà MODIFICATO.
 * @param k l'identificativo del veicolo interessato all'ADD. Richiesto nel confronto sulla matrice G.
 * @param tabooList indica la tabulist che include alcuni divieti su alcuni archi. Non inserire valore NULL
 * @param notWorseningMoves filtra i candidati sui soli miglioranti lo stato o che lo lascino invariato (sempre solo a livello di profit), sse posto a true.
 * @return MOVE_STATUS_OK sse una mossa viene effettivamente eseguita; MOVE_STATUS_FAIL altrimenti.
 */
int solveAddNeighbourhood(Pgraph p_graph, PvehicleState p_state, PGMatrix p_gMat, int k, PtabooList p_tabooList, TabooExpire now, pLOSConfiguration pLOSconfig, bool notWorseningMoves);

/** Mossa finale e confermata. Non ha precondizioni non banali perchè viene effettuata quando si è già certi che sia feasible
 * @param addTenure tenure per gli archi aggiunti in mossa ADD
 * @param removeTenure tenure per glia rchi rimossi in mossa ADD */
void makeAddMove(Pgraph p_graph, PvehicleState p_state, PGMatrix p_gMat, int k, PtabooList p_tabooList, TabooExpire now, PbestAddRemoveChoice p_best, int addTenure, int removeTenure);

/** Snellimento del codice. aggiorna una scelta migliore, \ref{BestAddRemoveChoice} */
void updateBestAddChoice(PbestAddRemoveChoice p_bestchoice, EdgeID e_il, EdgeID e_jl, EdgeID e_ij, Weight score);

/** computa la partizione dell'intorno ADD relativa a tutti i soli possibili 'archi doppi' inseribili.  */
void analyzeDoubleEdgeAddSubNeighbourhood(Pgraph p_graph, PvehicleState p_state, PGMatrix p_gMat,
										PtabooList p_taboo, TabooExpire now, PbestAddRemoveChoice p_best, PedgeID p_edge, int evaluateMode);

/** analizza gli effetti sull'improvement di un possibile candidato di tipo arco doppio (se feasible)
 * cosa deve assicurarsi?
 * \li l'arco non sia percorso
 * \li aggiungendolo si resti TQOK
 * \li la modifica sia concessa dalla TL o dai criteri
 * @return \li un punteggio diverso da zero e dal vecchio Jk se la mossa è possibile e cambia lo stato di raccolta
 * 		   \li un punteggio uguale al vecchio Jk se la mossa è possibile senza raccogliere (TODO controllare bontà di questa scelta!)
 * 	   	   \li 0 sse qualche condizione non è stata soddisfatta. */
Weight analyzeDoubleEdgeAddCandidate(Pgraph p_graph, EdgeID edge, PvehicleState p_state, PGMatrix p_gMat, PtabooList p_taboo, TabooExpire now, int evaluateMode);

/** computa la partizione dell'intorno ADD relativa alle triangolazioni possibili su e_{il} \in P_k
 * @param p_edge l'arco perno del sottointorno. */
void analyzeTriangleEdgeAddSubNeighbourhood(Pgraph p_graph, PvehicleState p_state, PGMatrix p_gMat, int k, PtabooList p_taboo, TabooExpire now,
											PbestAddRemoveChoice p_best, PedgeID p_edge, int evaluateMode);

/** analizza gli effetti sull'improvement di un possibile candidato di tipo arco triangolante (se feasible)
 * cosa deve assicurarsi?
 * \li l'arco non sia percorso
 * \li aggiungendolo si resti TQOK
 * \li la modifica sia concessa dalla TL o dai criteri
 * \li l'aggiunta migliori la funzione obiettivo del veicolo (cached in Jk)
 * @param p_edge arco 'perno' del triangolo.
 * @param p_sx parte 'sinistra' della triangolazione
 * @param p_dx parte 'destra' della triangolazione.
 *  @return \li un punteggio diverso da zero e dal vecchio Jk se la mossa è possibile e cambia lo stato di raccolta
 * 		   \li un punteggio uguale al vecchio Jk se la mossa è possibile senza raccogliere (TODO controllare bontà di questa scelta!)
 * 	   	   \li 0 sse qualche condizione non è stata soddisfatta. */
Weight analyzeTriangleEdgeAddCandidate(Pgraph p_graph, EdgeID p_edge, EdgeID p_sx, EdgeID p_dx,
									 PvehicleState p_state, PGMatrix p_gMat, int k, PtabooList p_taboo, TabooExpire now, int evaluateMode);

/**controlla se una mossa di tipo ADD modalita' doppi archi è accettabie secondo i criteri T e Q del grafo
 *
 * @param graph indica il grafo su cui deve essere applicata la mossa ADD
 * @param state indica lo stato del veicolo su cui applicare la mossa ADD
 * @param toadd1 indica l'arco da aggiungere al percorso
 * @param pgm un riferimento alla matrice ove controllare la raccoglibilità dell'edge: se non è possibile, è incorretto considerarla.
 * @return true sse la mossa di arco doppio è TQOK. */
bool isTQOKDoubleAdd(Pgraph graph, PvehicleState state, PGMatrix p_gMat, PedgeID toadd1);

/**controlla se una mossa di tipo ADD modalita' triangolante è accettabie secondo i criteri T e Q del grafo
 *
 * @param graph indica il grafo su cui deve essere applicata la mossa ADD
 * @param state indica lo stato del veicolo su cui aplicare la mossa ADD
 * @param toadd1 indica l'arco e_il da aggiungere al percorso
 * @param toadd1 indica l'arco e_jl da aggiungere al percorso
 * @param pgm un riferimento alla matrice ove controllare la raccoglibilità dell'edge: se non è possibile, è incorretto considerarla.
 * @return true sse la mossa triangolante è TQOK.
 */
bool isTQOKTriangleAdd(Pgraph graph, PvehicleState state, PGMatrix p_gMat, PedgeID toremove, PedgeID toadd1, PedgeID toadd2, int k);

#endif /* ADD_H_ */
